package com.sgj.utils;

import java.math.BigDecimal;

import static com.sgj.utils.ObjFormat.doubleFormat;

public class Arith {

    /**
     * 由于Java的简单类型不能够精确的对浮点数进行运算，这个工具类提供精
     * 确的浮点数运算，包括加减乘除和四舍五入。
     */
    private static final int DEF_DIV_SCALE = 10;
    private Arith(){
    }
    /**
     * 提供精确的加法运算。
     * @param v1 被加数
     * @param v2 加数
     * @return 两个参数的和
     */
    public static double add(double v1,double v2){
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.add(b2).doubleValue();
    }

    /**
     * 提供精确的减法运算。
     * @param v1 被减数
     * @param v2 减数
     * @return 两个参数的差
     */
    public static double sub(double v1,double v2){
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.subtract(b2).doubleValue();
    }
    /**
     * 提供精确的乘法运算。
     * @param v1 被乘数
     * @param v2 乘数
     * @return 两个参数的积
     */
    public static double mulMore(double v1, double v2){
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.multiply(b2).doubleValue();
    }
    /**
     * 提供（相对）精确的除法运算，当发生除不尽的情况时，精确到
     * 小数点以后10位，以后的数字四舍五入。
     * @param v1 被除数
     * @param v2 除数
     * @return 两个参数的商
     */
    public static double div(double v1,double v2){
        return div(v1,v2,DEF_DIV_SCALE);
    }
    /**
     * 提供（相对）精确的除法运算。当发生除不尽的情况时，由scale参数指
     * 定精度，以后的数字四舍五入。
     * @param v1 被除数
     * @param v2 除数
     * @param scale 表示表示需要精确到小数点以后几位。
     * @return 两个参数的商
     */
    public static double div(double v1,double v2,int scale){
        if(scale<0){
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
    }
    /**
     * 提供精确的小数位四舍五入处理。
     * @param v 需要四舍五入的数字
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     */
    public static double round(Double v,int scale){
        if(scale<0){
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        if(v==null){
            v=0D;
        }
        BigDecimal b = new BigDecimal(Double.toString(v));
        return b.setScale(scale,BigDecimal.ROUND_HALF_UP).doubleValue();
    }
    public static double round(Object v,int scale){
        return round(doubleFormat(v),scale);
    }


    /**
     * 提供精确的加法运算。
     * @param v1 被加数
     * @param v2 加数
     * @param vs 其余加数
     * @return 和
     */
    public static double addMore(Object v1,Object v2,Object... vs){
        double result = add(doubleFormat(v1), doubleFormat(v2));
        for(Object v:vs){
            result = add(result, doubleFormat(v));
        }
        return result;
    }
    /**
     * 提供精确的减法运算。
     * @param v1 被减数
     * @param v2 减数
     * @param vs 其余减数
     * @return 差
     */
    public static double subMore(Object v1,Object v2,Object... vs){
        double result = sub(doubleFormat(v1), doubleFormat(v2));
        for(Object v:vs){
            result = sub(result, doubleFormat(v));
        }
        return result;
    }
    /**
     * 提供（相对）精确的除法运算。当发生除不尽的情况时，由scale参数指
     * 定精度，以后的数字四舍五入。
     * @param v1 被除数
     * @param v2 除数
     * @return 两个参数的商
     */
    public static double div(Object v1,Object v2){

        if(v1==null) v1=0D;
        if(v2==null) v2=0D;
        BigDecimal b1 = new BigDecimal(v1.toString());
        BigDecimal b2 = new BigDecimal(v2.toString());
        return b1.divide(b2,DEF_DIV_SCALE,BigDecimal.ROUND_HALF_UP).doubleValue();
    }
    /**
     * 提供（相对）精确的除法运算。当发生除不尽的情况时，由scale参数指
     * 定精度，以后的数字四舍五入。
     * @param v1 被除数
     * @param v2 除数
     * @param scale 表示表示需要精确到小数点以后几位。
     * @return 两个参数的商
     */
    public static double div(Object v1,Object v2,int scale){
        if(scale<0){
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        if(v1==null) v1=0D;
        if(v2==null) v2=0D;
        BigDecimal b1 = new BigDecimal(v1.toString());
        BigDecimal b2 = new BigDecimal(v2.toString());
        return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
    }
    /**
     * 提供精确的除法运算。
     * @param v1 被除数
     * @param v2 除数
     * @param vs 其余除数
     * @return 商
     */
    public static double divMore(Object v1,Object v2,Object... vs){
        double result = div(v1, v2);
        for(Object v:vs){
            result = div(result, v);
        }
        return result;
    }
    /**
     * 提供精确的乘法运算。
     * @param v1 被乘数
     * @param v2 乘数
     * @return 两个参数的积
     */
    public static double mulMore(Object v1, Object v2, Object...vs){
        double result = mulMore(doubleFormat(v1), doubleFormat(v2));
        for(Object v:vs){
            result = mulMore(result, doubleFormat(v));
        }
        return result;
    }

    public static int ceil(Object v){
        Double result = Math.ceil(doubleFormat(v));
        return result.intValue();
    }
    public static int floor(Object v){
        Double result = Math.floor(doubleFormat(v));
        return result.intValue();
    }
    /**是否为奇数*/
    public static Boolean isOdd(int a) {
        return (a & 1) == 1;
    }
    /**向下取偶*/
    public static int floorEven(Object v) {
        int tmp = floor(v);
        if(isOdd(tmp)){
            return tmp-1;
        }else{
            return tmp;
        }
    }
    /**向上取偶*/
    public static int ceilEven(Object v) {
        int tmp = ceil(v);
        if(isOdd(tmp)){
            return tmp+1;
        }else{
            return tmp;
        }
    }
    public static boolean isNum(String str){
        return str.matches("^[-+]?(([0-9]+)([.]([0-9]+))?|([.]([0-9]+))?)$");
    }

}

